﻿//    Copyright 2014 LuoZhihui
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//      http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.

#region  导入名称空间

using System;
using System.Collections.Generic;
using LotteryEngine.Infrastructure.Querying;
using NHibernate;
using NHibernate.Criterion;

#endregion

namespace LotteryEngine.Repository.NHibernate.Repositories
{
	public static class QueryTranslator
	{
		public static ICriteria TranslateIntoNHQuery<T>(this Query query,
			ICriteria criteria)
		{
			BuildQueryFrom(query, criteria);

			if (query.OrderByProperty != null)
				criteria.AddOrder(new Order(query.OrderByProperty.PropertyName,
					!query.OrderByProperty.Desc));

			return criteria;
		}

		private static void BuildQueryFrom(Query query, ICriteria criteria)
		{
			IList<ICriterion> critrions = new List<ICriterion>();

			if (query.Criteria != null)
			{
				foreach (var c in query.Criteria)
				{
					ICriterion criterion;

					switch (c.CriteriaOperator)
					{
						case CriteriaOperator.Eq:
							criterion = Restrictions.Eq(c.PropertyName, c.Value);
							break;
						case CriteriaOperator.Le:
							criterion = Restrictions.Le(c.PropertyName, c.Value);
							break;
						case CriteriaOperator.Ge:
							criterion = Restrictions.Ge(c.PropertyName, c.Value);
							break;
						case CriteriaOperator.Lt:
							criterion = Restrictions.Lt(c.PropertyName, c.Value);
							break;
						case CriteriaOperator.Gt:
							criterion = Restrictions.Gt(c.PropertyName, c.Value);
							break;


						default:
							throw new ApplicationException("No operator defined");
					}

					critrions.Add(criterion);
				}

				if (query.QueryOperator == QueryOperator.And)
				{
					var andSubQuery = Restrictions.Conjunction();
					foreach (var criterion in critrions)
					{
						andSubQuery.Add(criterion);
					}

					criteria.Add(andSubQuery);
				}
				else
				{
					var orSubQuery = Restrictions.Disjunction();
					foreach (var criterion in critrions)
					{
						orSubQuery.Add(criterion);
					}
					criteria.Add(orSubQuery);
				}

				foreach (var sub in query.SubQueries)
				{
					BuildQueryFrom(sub, criteria);
				}
			}
		}
	}
}